package com.atguigu.java.ai.langchain4j.tools;

import com.atguigu.java.ai.langchain4j.utils.ImageClickUtils;
import dev.langchain4j.agent.tool.P;
import dev.langchain4j.agent.tool.Tool;
import io.appium.java_client.AppiumBy;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.nativekey.AndroidKey;
import io.appium.java_client.android.nativekey.KeyEvent;
import org.openqa.selenium.By;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.PointerInput;
import org.openqa.selenium.interactions.Sequence;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.springframework.stereotype.Component;

import java.net.MalformedURLException;
import java.net.URL;
import java.time.Duration;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;


@Component
public class TransferTools {
    //平台名称
    public static final String PLATFORM_NAME = "ANDROID";
    //设备名称
    public static final String DEVICE_NAME = "OPPO R11";
    //设备udid
    public static final String DEVICE_UDID = "f905ac0e";
    // 自动化引擎
    public static final String AUTOMATION_NAME = "UiAutomator2";
    //自动授权
    public static final boolean AUTO_GRANT_PERMISSIONS = true;
    //f绕过UI层级截图
    public static final boolean FORCE_NATIVE_SCREENSHOT = true;
    //禁用WebView检查
    public static final boolean ENSURE_WEBVIEWS_HAVE_PAGES = false;


    private AndroidDriver initializeAppiumDriver() {
        DesiredCapabilities capabilities = new DesiredCapabilities();
        capabilities.setCapability("appium:platformName", PLATFORM_NAME);
        capabilities.setCapability("appium:deviceName", DEVICE_NAME);
        capabilities.setCapability("appium:udid", DEVICE_UDID);
        capabilities.setCapability("appium:automationName", AUTOMATION_NAME);
        capabilities.setCapability("appium:autoGrantPermissions", AUTO_GRANT_PERMISSIONS);
        capabilities.setCapability("appium:forceNativeScreenshot", FORCE_NATIVE_SCREENSHOT);
        capabilities.setCapability("appium:ensureWebviewsHavePages", ENSURE_WEBVIEWS_HAVE_PAGES);

        try {
            URL serverUrl = new URL("http://127.0.0.1:4723");
            return new AndroidDriver(serverUrl, capabilities);
        } catch (MalformedURLException e) {
            throw new RuntimeException("Invalid Appium server URL", e);
        }
    }

    @Tool(name = "转账", value = "根据参数信息进行转账")
    public void transfer(
            @P(value = "转账金额") Double amount,
            @P(value = "转账账户名称") String accountName,
            @P(value = "转账账户密码") String password
    ) {
        // 金额校验
        if (amount <= 0) {
            throw new IllegalArgumentException("转账金额必须大于0");
        }
        if (amount > 1000000) {
            throw new IllegalArgumentException("单笔转账金额不能超过100万");
        }

        AndroidDriver driver = initializeAppiumDriver();

        // 创建WebDriver实例
        // 1、点击转账汇款，xpath android.widget.ImageView[@resource-id="cn.com.njcb.android.mobilebank:id/home_big_menu_img"][3]
        // 显式等待元素加载
        By versionLocator = AppiumBy.xpath(
                "(//android.widget.ImageView[@resource-id=\"cn.com.njcb.android.mobilebank:id/home_big_menu_img\"])[3]"
        );
        WebElement versionElement = new WebDriverWait(driver, Duration.ofSeconds(10))
                .until(ExpectedConditions.elementToBeClickable(versionLocator));

        versionElement.click();  // 执行点击操作


        //2. 点击最近转账人王平
        By versionLocator1 = AppiumBy.xpath(String.format("//android.view.View[@text=\"%s\"]", accountName));

        WebElement versionElement1 = new WebDriverWait(driver, Duration.ofSeconds(10))
                .until(ExpectedConditions.elementToBeClickable(versionLocator1));

        versionElement1.click();  // 执行点击操作

        // 3.点击免手续费输入框，输入转账金额20 xpath =  //android.widget.EditText[@resource-id="vux-x-input-fw-gen-10004"]
        // 3. 输入转账金额
        By amountLocator = AppiumBy.xpath(
                "//android.widget.EditText[@resource-id='vux-x-input-fw-gen-10004']"
        );
        WebElement amountInput = new WebDriverWait(driver, Duration.ofSeconds(15))
                .until(ExpectedConditions.elementToBeClickable(amountLocator));
        amountInput.click();
        // 生成 1 到 10 的随机数
//            int randomNumber = new Random().nextInt(10) + 1;

        //调用安全键盘输入核心方法
        inputSecurityAmount(driver, amount);

        // 5. 点击下一步按钮（优化定位策略）
        By nextStepLocator = AppiumBy.xpath(
                "//android.widget.Button[contains(@text, '下一步')]"
        );

        WebElement nextStepButton = new WebDriverWait(driver, Duration.ofSeconds(15))
                .until(ExpectedConditions.elementToBeClickable(nextStepLocator));
        nextStepButton.click();

        // 5. 点击下一步按钮（优化定位策略）
        By qrStepLocator = AppiumBy.xpath(
                "//android.widget.Button[@text=\"确认转账 \"]"
        );

        WebElement qrStepButton = new WebDriverWait(driver, Duration.ofSeconds(15))
                .until(ExpectedConditions.elementToBeClickable(qrStepLocator));
        qrStepButton.click();

//            String pasword = "147258";
        inputSecurityAmount(driver, password);

    }


    @Tool(name = "鑫元宝", value = "根据参数信息进行鑫元宝的购买")
    public void xinYuanBao(
            @P(value = "金额") Double amount,
            @P(value = "密码") String password
    ) throws InterruptedException {
        // 金额校验
        if (amount <= 0) {
            throw new IllegalArgumentException("转账金额必须大于0");
        }
        if (amount > 1000000) {
            throw new IllegalArgumentException("单笔转账金额不能超过100万");
        }

        AndroidDriver driver = initializeAppiumDriver();
        // 创建WebDriver实例

        //1、点击投资理财页签 //android.widget.RadioButton[@resource-id="cn.com.njcb.android.mobilebank:id/rbTabFinance"]
        By versionLocator = AppiumBy.xpath(
                "//android.widget.RadioButton[@resource-id=\"cn.com.njcb.android.mobilebank:id/rbTabFinance\"]"
        );
        WebElement versionElement = new WebDriverWait(driver, Duration.ofSeconds(10))
                .until(ExpectedConditions.elementToBeClickable(versionLocator));
        versionElement.click();
        //2、点击鑫元宝  //android.widget.TextView[@resource-id="cn.com.njcb.android.mobilebank:id/home_tvName" and @text="鑫元宝"]
        By versionLocator1 = AppiumBy.xpath(
                "//android.widget.TextView[@resource-id=\"cn.com.njcb.android.mobilebank:id/home_tvName\" and @text=\"鑫元宝\"]"
        );
        WebElement versionElement1 = new WebDriverWait(driver, Duration.ofSeconds(10))
                .until(ExpectedConditions.elementToBeClickable(versionLocator1));
        versionElement1.click();
        Thread.sleep(3000);
        ; // 等待页面稳定再滑动
        //3。向上滑动
        swipeUp(driver);

        By versionLocator2 = AppiumBy.xpath(
                "//android.widget.Button[@text=\"购买 \"]"
        );
        //4.点击购买  //android.widget.Button[@text="购买 "]
        WebElement versionElement2 = new WebDriverWait(driver, Duration.ofSeconds(10))
                .until(ExpectedConditions.elementToBeClickable(versionLocator2));
        versionElement2.click();


        //5.点击金额的input框 //android.widget.EditText[@resource-id="vux-x-input-fw-gen-10001"]
        By versionLocator3 = AppiumBy.xpath(
                "//android.widget.EditText[@resource-id=\"vux-x-input-fw-gen-10001\"]"
        );
        WebElement versionElement3 = new WebDriverWait(driver, Duration.ofSeconds(10))
                .until(ExpectedConditions.elementToBeClickable(versionLocator3));
        versionElement3.click();

        //6输入金额并关闭虚拟键盘
        inputSecurityAmount(driver, amount);

        ImageClickUtils.clickByImage(driver, "C:\\project\\java-ai-langchain4j\\src\\main\\resources\\imgs\\xybfwxy.png");
        swipeToBottom(driver, 10);

        By versionLocator31 = AppiumBy.xpath(
                "//android.widget.ImageView"
        );
        WebElement versionElement31 = new WebDriverWait(driver, Duration.ofSeconds(10))
                .until(ExpectedConditions.elementToBeClickable(versionLocator31));
        versionElement31.click();

        //7、然后点击我已阅读 //android.view.View[@resource-id="P041303"]/android.view.View[4]/android.view.View[3]
        By versionLocator4 = AppiumBy.xpath(
                "//android.widget.Image[@text=\"MYa1HxXjHAnD2YA8MkasXjpKJ6zHoLmBumNRnyWc8xAS8mILjkfXICac+cHDCOmnNB2awJxxZwakPeeEq+SX5+CbqPxn4DTYwXsEM9h9nelHADlLLYgAAAABJRU5ErkJggg==\"]"
        );
        WebElement versionElement4 = new WebDriverWait(driver, Duration.ofSeconds(10))
                .until(ExpectedConditions.elementToBeClickable(versionLocator4));
        versionElement4.click();
//        //8.点击购买 //android.widget.Button[@text="确定购买 "]
//        By confirmLocator = AppiumBy.xpath(
//                "//android.widget.Button[@text='确定购买 '");
//
//        WebElement confirmButton = new WebDriverWait(driver, Duration.ofSeconds(10))
//                .until(ExpectedConditions.presenceOfElementLocated(confirmLocator));
//            confirmButton.click();
//            //输入密码
//        inputSecurityAmount(driver, password);

    }



    // 安全键盘输入核心方法
    private void inputSecurityAmount(AndroidDriver driver, String amount) {

        // 字符映射表
        Map<Character, String> keyMapping = new HashMap<>();
        keyMapping.put('0', "//android.widget.Button[@content-desc='0']");
        keyMapping.put('1', "//android.widget.Button[@content-desc='1']");
        keyMapping.put('2', "//android.widget.Button[@content-desc='2']");
        keyMapping.put('3', "//android.widget.Button[@content-desc='3']");
        keyMapping.put('4', "//android.widget.Button[@content-desc='4']");
        keyMapping.put('5', "//android.widget.Button[@content-desc='5']");
        keyMapping.put('6', "//android.widget.Button[@content-desc='6']");
        keyMapping.put('7', "//android.widget.Button[@content-desc='7']");
        keyMapping.put('8', "//android.widget.Button[@content-desc='8']");
        keyMapping.put('9', "//android.widget.Button[@content-desc='9']");
        keyMapping.put('.', "//android.widget.Button[@content-desc='句点']");

        // 逐个输入数字
        for (char c : amount.toCharArray()) {
            By keyLocator = AppiumBy.xpath(keyMapping.get(c));
            new WebDriverWait(driver, Duration.ofSeconds(5))
                    .until(ExpectedConditions.elementToBeClickable(keyLocator))
                    .click();
        }

        // 关闭键盘
        clickCompleteButton(driver);
    }

    // 金额输入方法增强
    private void inputSecurityAmount(AndroidDriver driver, Double amount) {
        String amountStr = String.format("%.2f", amount);  // 格式化为两位小数

        // 增强的键盘映射表
        Map<Character, String> keyMapping = new HashMap<>();
        keyMapping.put('0', "//*[contains(@content-desc,'0')]");
        keyMapping.put('1', "//*[contains(@content-desc,'1')]");
        keyMapping.put('2', "//*[contains(@content-desc,'2')]");
        keyMapping.put('3', "//*[contains(@content-desc,'3')]");
        keyMapping.put('4', "//*[contains(@content-desc,'4')]");
        keyMapping.put('5', "//*[contains(@content-desc,'5')]");
        keyMapping.put('6', "//*[contains(@content-desc,'6')]");
        keyMapping.put('7', "//*[contains(@content-desc,'7')]");
        keyMapping.put('8', "//*[contains(@content-desc,'8')]");
        keyMapping.put('9', "//*[contains(@content-desc,'9')]");
        keyMapping.put('.', "//*[contains(@content-desc,'句点') or contains(@content-desc,'点')]");

        // 安全输入
        for (char c : amountStr.toCharArray()) {
            try {
                new WebDriverWait(driver, Duration.ofSeconds(3))
                        .until(ExpectedConditions.elementToBeClickable(
                                AppiumBy.xpath(keyMapping.get(c))
                        )).click();
                Thread.sleep(200);  // 输入间隔
            } catch (Exception e) {
                // 备用输入方案
                driver.pressKey(new KeyEvent(AndroidKey.DEL));
                throw new RuntimeException("输入数字" + c + "失败");
            }
        }
        // 关闭键盘
        clickCompleteButton(driver);
    }

    // 辅助方法：点击完成按钮
    private void clickCompleteButton(AndroidDriver driver) {
        By completeLocator = AppiumBy.xpath("//android.widget.Button[@content-desc='完成']");
        new WebDriverWait(driver, Duration.ofSeconds(5))
                .until(ExpectedConditions.elementToBeClickable(completeLocator))
                .click();
    }

    /**
     * 向上滑动
     *
     * @param driver
     * @throws InterruptedException
     */
    private void swipeUp(AndroidDriver driver) throws InterruptedException {
        Dimension size = driver.manage().window().getSize();
        int startY = (int) (size.getHeight() * 0.7);
        int endY = (int) (size.getHeight() * 0.3);

        // 使用组合定位策略：resource-id + 模糊文本匹配
        By versionLocator = AppiumBy.xpath(
                "//android.widget.Button[@text=\"购买 \"]"
        );

        // 最多滑动3次
        for (int i = 0; i < 3; i++) {
            try {
                WebElement versionElement = driver.findElement(versionLocator);
                if (versionElement.isDisplayed()) {
                    return; // 找到元素立即返回
                }
            } catch (NoSuchElementException e) {
                performSwipe(driver, startY, endY);
                Thread.sleep(1500);// 滑动后等待页面稳定
            }
        }
    }

    //--- 辅助方法 ---//

    /**
     * 执行滑动操作（W3C标准）
     *
     * @param driver  AndroidDriver 实例
     * @param startY  滑动的起始Y坐标
     * @param endY    滑动的结束Y坐标
     */
    private void performSwipe(AndroidDriver driver, int startY, int endY) {

        // 创建一个触摸输入设备，命名为 "finger"
        PointerInput finger = new PointerInput(PointerInput.Kind.TOUCH, "finger");

        // 创建一个动作序列，并与上面创建的 "finger" 关联
        Sequence swipe = new Sequence(finger, 0);

        // 获取屏幕尺寸，用于计算滑动的起点和终点位置
        Dimension size = driver.manage().window().getSize();

        // 将手指移动到滑动的起始位置（不按下）
        swipe.addAction(finger.createPointerMove(Duration.ZERO, PointerInput.Origin.viewport(), size.getWidth() / 2, startY));

        // 在起始位置按下手指，模拟触屏按下操作
        swipe.addAction(finger.createPointerDown(PointerInput.MouseButton.LEFT.asArg()));

        // 在屏幕上从起始位置滑动到结束位置，持续时间为800毫秒
        swipe.addAction(finger.createPointerMove(Duration.ofMillis(800), PointerInput.Origin.viewport(), size.getWidth() / 2, endY));

        // 抬起手指，模拟触屏释放操作
        swipe.addAction(finger.createPointerUp(PointerInput.MouseButton.LEFT.asArg()));

        // 执行上述滑动操作
        driver.perform(Collections.singletonList(swipe));
    }

    /**
     * 滑动到页面底部（通用方法）
     *
     * @param driver       AndroidDriver 实例
     * @param swipeCount   最大尝试滑动次数（防止无限循环）
     */
    public void swipeToBottom(AndroidDriver driver, int swipeCount) throws InterruptedException {
        Dimension size = driver.manage().window().getSize();
        int startY = (int) (size.getHeight() * 0.8);
        int endY = (int) (size.getHeight() * 0.2);

        String previousPageSource = "";
        String currentPageSource;

        for (int i = 0; i < swipeCount; i++) {
            currentPageSource = driver.getPageSource();

            // 如果当前页面与上次相同，说明已经滑动到底部
            if (currentPageSource.equals(previousPageSource)) {
                System.out.println("已滑动到底部，第 " + (i + 1) + " 次滑动后停止");
                break;
            }
            // 执行滑动操作
            performSwipe(driver, startY, endY);
            Thread.sleep(1500);// 滑动后等待页面稳定

            // 更新页面源码记录
            previousPageSource = currentPageSource;
        }
    }

}
